package edu.gatech.spacetraderteam3.view;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.Arrays;

/**
 * A class that represents a drop down menu on the GUI
 * @author Alexander Ikonomidis
 * @version 1.0
 * @param <T>
 */
public class SGGDropDownBox<T> extends SGGComponent {

    /**
     * The options listed in the menu
     */
    private final T[] options;

    /**
     * The boolean value used to dictate whether the box is
     * expanded or not and whether the mouse has released clicking
     */
    private boolean expanded = false, mouseReleased = true;

    /**
     * The selected value from the menu
     */
    private int selectedValue = 0;

    /**
     * The height of each row in the drop down menu
     */
    private int lineHeight = 0;

    /**
     * Dictates how many characters wide the drop down box is
     */
    private final int buffer = 10;

    /**
     * Half the buffer size
     */
    private final int halfBuffer = buffer / 2;

    /**
     * Constructor for drop down box. Contains list of options and the selected choice
     * @param options Options contained within the drop down box
     * @param selectedValue Selected option's index
     */
    protected SGGDropDownBox(T[] options, int selectedValue) {
        super(100, 30);
        this.options = options;
        this.selectedValue = Math.max(0, Math.min(selectedValue, options.length));
    }

    /**
     * Paints the drop down box. Painting depends on whether it is expanded or not
     * @param g Graphics component to paint on
     */
    public void doPaint(Graphics2D g) {
        String display = options[selectedValue].toString();
        lineHeight = g.getFontMetrics().getHeight();
        int lineWidth = g.getFontMetrics().stringWidth(display + "...");
        while (lineWidth + halfBuffer > getWidth()) {

            display = display.substring(0, display.length() - 1);
            lineWidth = g.getFontMetrics().stringWidth(display + "...");
        }

        display += "...";

        if (expanded) {
            g.setColor(Color.WHITE);
            g.fillRect(getX(), getY(), getWidth(), (lineHeight + buffer) * options.length);

            g.setColor(color);
            for (int i = 0; i < options.length; i++) {

                display = options[i].toString();
                lineHeight = g.getFontMetrics().getHeight();
                lineWidth = g.getFontMetrics().stringWidth(display + "...");
                if (lineWidth + halfBuffer > getWidth()) {
                    while (lineWidth + halfBuffer > getWidth()) {

                        display = display.substring(0, display.length() - 1);
                        lineWidth = g.getFontMetrics().stringWidth(display + "...");
                    }

                    display += "...";
                }
                g.drawString(display, getX() + halfBuffer, getY()
                        + (lineHeight + halfBuffer) * (i + 1) + (i * halfBuffer));

            }
            setDimensions(getWidth(), (lineHeight + halfBuffer) * (options.length + 1)
                    + (options.length * halfBuffer));
        } else {
            g.setColor(Color.WHITE);
            setDimensions(getWidth(), lineHeight + buffer);
            g.fillRect(getX(), getY(), getWidth(), getHeight());
            g.setColor(color);
            g.drawString(display, getX() + halfBuffer, getY() + lineHeight);

        }
    }

    /**
     * Getter for the selected selected value
     * @return Selected value
     */
    public T getValue() {
        return options[selectedValue];
    }

    /**
     * Setter for a specific option of the drop down menu 
     * @param index Index of the drop down menu item
     */
    public void setValue(int index) {
        selectedValue = Math.min(Math.max(index, options.length - 1), 0);
    }

    /**
     * Getter for the index of the selected item
     * @return The index
     */
    public int getSelectedIndex() {
        return selectedValue;
    }

    /**
     * Sets mouseReleased to false. If not expanded, expands the drop down box, If expanded, changes 
     * the selected value and unexpands the drop down box. Finally, requests repaint
     * @param p Point that was clicked
     */
    protected void doClick(Point p) {
        if (mouseReleased) {
            if (!expanded) {
                expanded = true;
            } else {
                for (int i = 0; i < options.length; i++) {
                    if (p.getX() > getX() && p.getX() < getX() + getWidth()) {
                        if (getY() + ((lineHeight + buffer) * i) < p.getY()
                                && p.getY() < getY() + ((lineHeight + buffer) * (i + 1))) {
                            selectedValue = i;
                            expanded = false;
                            sggEventListener.doEvent(new SGGEvent(
                                    "Drop down box value changed.", this));
                            break;
                        }
                    }
                }
            }
        }
        mouseReleased = false;
        SGGWM.requestRepaint();
    }

    /**
     * Sets mouse released to true. 
     */
    protected void doRelease() {
        mouseReleased = true;
    }

    /**
     * Sets expanded to false when losing focus
     */
    protected void loseFocus() {
        expanded = false;
    }

    /**
     * @return the list of options.
     */
    public String toString() {
        return Arrays.toString(options);
    }
}
